﻿/*
	Copyright (C) 2019 Zongming Liu <1849059316@qq.com>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.
	
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
	
	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "LineEdit.h"
#include "../base/EventMouse.h"
#include "../node/Sprite.h"
#include "Text.h"
#include "../base/CharacterEvent.h"
#include "../base/Debuger.h"
#include "../render/Camera.h"
#include "Geometry.h"
#include <cwctype>
#include <locale>
#include "../base/GameWorld.h"
#include "../render/IRender.h"
#include "../base/EventKey.h"
#include "Scale9Image.h"
#include "../base/EventWidgetMove.h"

namespace SkyEngine2d
{
	
	LineEdit* LineEdit::create(const std::wstring& background_img, const Rect& cap_insets /*= Rect::Zero*/, Widget* parent /*= nullptr*/)
	{
		auto w = makeWidgetPtr(parent);
		if (w && w->init(background_img, cap_insets))
		{
			return w;
		}
	
		return nullptr;
	}
	
	LineEdit* LineEdit::create(Widget* parent/*= nullptr*/)
	{
		auto w = makeWidgetPtr(parent);
		if (w && w->init(L""))
		{
			return w;
		}
	
		return nullptr;
	}
	
	LineEdit::LineEdit(Widget* parent)
		:Widget(parent)
		, m_drawCount(0)
		, m_textLen(0)
		, m_dragAnchorIdx(0)
		, m_currentAnchorIdx(0)
		, m_isBeginSelectText(false)
		, m_selectionEnd(0)
		, m_selectionStart(0)
		, m_textRender(nullptr)
	{
	}
	
	LineEdit::~LineEdit()
	{
	
	}
	
	void LineEdit::setSelection(int start_pos, int end_pos)
	{
		//限制范围
		int startPos = start_pos > m_textLen ? m_textLen : start_pos;
		int endPos = end_pos > m_textLen ? m_textLen : end_pos;
		//调整顺讯
		if (startPos > endPos)
		{
			std::swap(startPos, endPos);
		}
		//改变选择的状态
		if ((startPos != m_selectionStart) || (endPos != m_selectionEnd))
		{
			m_selectionStart = startPos;
			m_selectionEnd = endPos;
	
			//触发选择改变事件
			//TODO 没有实现选择改变的事件
		}
	
	}
	
	void LineEdit::clearSelection()
	{
		if (getSelectionLen() != 0)
		{
			setSelection(0, 0);
		}
	}
	
	int LineEdit::getSelectionLen()
	{
		return m_selectionEnd - m_selectionStart;
	}
	
	int LineEdit::getTextIndexByPostion(const Vector2& pos)
	{
		if (m_textLen == 0)
		{
			return 0;
		}
	
		float text_pos = m_geometry.origin.x;
	
		float last_text_pos = text_pos;
	
		int index = 0;
		for (auto ch : m_text)
		{
			index++;
	
			auto w = getCharWidth(ch);
			text_pos += w;
			last_text_pos = text_pos;
	
			if (text_pos - w / 2 >= pos.x)
			{
				if ((text_pos - pos.x) > (pos.x - last_text_pos))
				{
					return index - 1;
				}
				return index;
			}
		}
	
		return index;
	}
	
	void LineEdit::draw(IRender* render, const Matrix4X4& transform)
	{
		DirectX::XMMATRIX mvp = DirectX::XMMatrixMultiply(transform, getCamera()->getViewProjectMat());
		if (m_currentBgImag)
		{
			m_currentBgImag->draw(render, mvp);
		}
	
		auto mat = getCamera()->getViewMat();
		mvp = DirectX::XMMatrixMultiply(transform, mat);
	
		displaySelection(render);
	
		m_textRender->draw(render, mvp);
	
		displayerCursor(render);
	
	}
	
	void LineEdit::setAnchorIndex(int index)
	{
		if (index >= 0 && index <= m_textLen && index != m_currentAnchorIdx)
		{
			m_currentAnchorIdx = index;
			auto pos = getPosXByIndex(m_currentAnchorIdx);
			m_cursorPosStart.x = pos;
			m_cursorPosEnd.x = pos;
		}
	}
	
	
	const std::wstring& LineEdit::getText() const
	{
		return m_text;
	}
	
	void LineEdit::setText(const std::wstring& text)
	{
		m_text = text;
		m_textLen = m_text.size();
		if (m_currentAnchorIdx > m_textLen)
		{
			this->setAnchorIndex(m_textLen);
		}
	}
	
	void LineEdit::setMaskChar(wchar_t ch)
	{
		m_maskCode = ch;
	}
	
	bool LineEdit::init(const std::wstring& background_img, const Rect& cap_insets /*= Rect::Zero*/)
	{
		if (!Widget::init())
		{
			return false;
		}
	
		if (background_img.size() > 0)
		{
			this->setBackgroundImage(background_img, cap_insets);
		}
	
		m_textRender = std::make_unique<Text>(m_text);
		m_textRender->setDrawRect(m_geometry);
	
		m_textRender->getFont().setAlignment(AlignLeft);
	
		return true;
	}
	
	void LineEdit::onKeyPressEvent(EventKey* event)
	{
		Widget::onKeyPressEvent(event);
	
		auto key = event->getKey();
		switch (key)
		{
		case VK_BACK:
		{
			this->handleBackspace();
			break;
		}
		case VK_LEFT:
		case VK_RIGHT:
		{
			this->handleArrow(key);
			break;
		}
		default:
			break;
		}
		event->accept();
	}
	
	void LineEdit::onKeyReleaseEvent(EventKey* event)
	{
		event->accept();
	}
	
	void LineEdit::onMousePressEvent(EventMouse* event)
	{
		//先处理基类的逻辑
		Widget::onMousePressEvent(event);
	
		if (event->getButton() == EventMouse::ButtonType::Left)
		{
			//清空选中的状态
			clearSelection();
			m_isBeginSelectText = true;
			Vector2 pos(event->getCurrentPosX(), event->getCurrentPosY());
			auto currentAnchorIdx = getTextIndexByPostion(pos);
			m_currentAnchorIdx = currentAnchorIdx;
			auto cursor_x = getPosXByIndex(m_currentAnchorIdx);
			m_cursorPosStart.x = cursor_x;
			m_cursorPosEnd.x = cursor_x;
			m_dragAnchorIdx = currentAnchorIdx;
		}
		event->accept();
	}
	
	void LineEdit::onMouseReleaseEvent(EventMouse* event)
	{
		Widget::onMouseReleaseEvent(event);
	
		if (m_isBeginSelectText)
		{
			m_isBeginSelectText = false;
			Vector2 pos(event->getCurrentPosX(), event->getCurrentPosY());
			auto index = getTextIndexByPostion(pos);
			setAnchorIndex(index);
			setSelection(m_dragAnchorIdx, index);
		}
		event->accept();
	}
	
	void LineEdit::onMouseMoveEvent(EventMouse* event)
	{
		Widget::onMouseMoveEvent(event);
	
		if (m_isBeginSelectText)
		{
			Vector2 pos(event->getCurrentPosX(), event->getCurrentPosY());
			auto index = getTextIndexByPostion(pos);
			setAnchorIndex(index);
			setSelection(m_dragAnchorIdx, index);
			DebugInfor("start:%d - - end:%d", m_selectionStart, m_selectionEnd);
		}
	}
	
	
	
	
	
	void LineEdit::onCharacterEvent(EventCharacter* e)
	{
		Widget::onCharacterEvent(e);
	
		auto ch = e->getCh();
	
		if (ch == '\t' || ch == '\r' || ch == '\n' || ch == '\r\n' || ch == '\b')
		{
			return;
		}
	
		if (getSelectionLen() > 0)
		{
			this->handleBackspace();
		}
	
		m_text.insert(m_currentAnchorIdx, 1, ch);
	
		auto font_size = getCharWidth(ch);
		m_cursorPosStart.x += font_size;
		m_cursorPosEnd.x += font_size;
	
		++m_currentAnchorIdx;
	
		++m_textLen;
	
		m_textRender->setText(m_text);
		e->accept();
	}
	
	void LineEdit::displayerCursor(IRender* render)
	{
		++m_drawCount;
		if (hasFocus())
		{
			if (m_drawCount > 30)
			{
				Geometry::drawLine(render,
					m_cursorPosStart,
					m_cursorPosEnd,
					Color::Red, 1);
				if (m_drawCount > 60)
				{
					m_drawCount = 0;
				}
			}
		}
		else
		{
			m_drawCount = 0;
		}
	}
	
	void LineEdit::displaySelection(IRender* render)
	{
		auto start = m_selectionStart;
		auto end = m_selectionEnd;
	
		if (getSelectionLen() == 0)
		{
			return;
		}
	
		m_selectionRect.origin.x = getPosXByIndex(start);
		m_selectionRect.size.width = getPosXByIndex(end) - m_selectionRect.origin.x;
	
		Geometry::drawFilledRect(render, m_selectionRect, Color::Blue);
	
	}
	
	float LineEdit::getPosXByIndex(int index)
	{
		if (index < 0)
		{
			return m_geometry.origin.x;
		}
		if (index > m_textLen)
		{
			return m_geometry.origin.x + m_geometry.size.width;
		}
	
		auto w = m_geometry.origin.x;
	
		for (int i = 0; i < index; i++)
		{
			w += getCharWidth(m_text[i]);
		}
		return w;
	}
	
	float LineEdit::getCharWidth(wchar_t ch)
	{
		auto font_size = m_textRender->getFont().getFontSize();
		auto half = font_size / 2;
	
		if (ch > 0X007e)
		{
			return font_size;
		}
		else
		{
			return half;
		}
	}
	
	void LineEdit::handleBackspace()
	{
		//先判断是不是有选区
		int selection_len = this->getSelectionLen();
		if (selection_len > 0)
		{
			//光标是否需要移动
			if (m_currentAnchorIdx == m_selectionEnd)
			{
				this->moveCursorL(selection_len);
			}
			m_text.erase(m_currentAnchorIdx, selection_len);
			m_textRender->setText(m_text);
			m_textLen -= selection_len;
			this->clearSelection();
			return;
		}
		else
		{
			if (m_currentAnchorIdx < 1)
			{
				return;
			}
	
			this->moveCursorL();
	
			m_text.erase(m_currentAnchorIdx, 1);
			m_textRender->setText(m_text);
			m_textLen--;
		}
		return;
	}
	
	void LineEdit::handleArrow(int key)
	{
		if (key == VK_LEFT)
		{
			this->moveCursorL();
		}
		else if (key == VK_RIGHT)
		{
			this->moveCursorR();
		}
	}
	
	void LineEdit::moveCursorL(int n)
	{
		DebugerAssert(n > 0, "错误 光标的偏移不能为0");
		for (int i = 0; i < n; i++)
		{
			if (m_currentAnchorIdx < 1)
			{
				return;
			}
			wchar_t ch = m_text[--m_currentAnchorIdx];
			auto x = this->getCharWidth(ch);
			m_cursorPosStart.x -= x;
			m_cursorPosEnd.x -= x;
		}
		clearSelection();
	}
	
	void LineEdit::moveCursorR(int n)
	{
		DebugerAssert(n > 0, "错误 光标的偏移不能为0");
		for (int i = 0; i < n; i++)
		{
			if (m_currentAnchorIdx >= m_textLen)
			{
				return;
			}
			wchar_t ch = m_text[m_currentAnchorIdx++];
			auto x = this->getCharWidth(ch);
			m_cursorPosStart.x += x;
			m_cursorPosEnd.x += x;
		}
	
		clearSelection();
	}
	
	void LineEdit::onResizeEvent(EventResize* e)
	{
		Widget::onResizeEvent(e);
	
		m_cursorPosStart.y = m_geometry.origin.y + 5;
		m_cursorPosEnd.y = m_geometry.size.height + m_geometry.origin.y - 5;
	
		m_selectionRect.origin.y = m_geometry.origin.y + 5;
		m_selectionRect.size.height = m_geometry.size.height - 10;
	}
	
	void LineEdit::onWidgetStateChange()
	{
		this->updateStyleInfo();
	}
	
	void LineEdit::onWidgetStyleChange()
	{
		this->updateStyleInfo();
	}
	
	void LineEdit::updateStyleInfo()
	{
		auto p = getStyleInfor();
		if (p)
		{
			if (p->backgroundImage)
			{
				m_currentBgImag = p->backgroundImage.get();
			}
	
			if (m_textRender)
			{
				m_textRender->setColor(p->textColor);
				m_textRender->setFont(p->textFont);
			}
		}
		else
		{
			auto pp = getStyleInforByState(Widget::WidgetState::Normal);
			m_currentBgImag = pp->backgroundImage.get();
		}
	}
	
	int LineEdit::getDefultWidth() const
	{
		return 180;
	}
	
	int LineEdit::getDefultHeight() const
	{
		return 50;
	}
	
	void LineEdit::onMoveEvent(EventWidgetMove* e)
	{
		Widget::onMoveEvent(e);
	
		m_cursorPosStart.y = m_geometry.origin.y + 5;
		m_cursorPosEnd.y = m_geometry.size.height + m_geometry.origin.y - 5;
	
		m_selectionRect.origin.y = m_geometry.origin.y + 5;
	}
	
}
